<?php
declare(strict_types=1);

namespace App\Chat\Service;

use App\Chat\Cache\LastMessage;
use App\Chat\Cache\ServerRunID;
use App\Chat\Cache\UnreadTalkCache;
use App\Chat\Constant\TalkModeConstant;
use App\Common\Constants\GenderConstants;
use App\Common\Robot\Robot;
use App\CustHub\Constants\ContactStatusConstants;
use App\CustHub\Constants\MsgTypeConstants;
use App\CustHub\Mapper\ChCustomerServiceMapper;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Model\ChContact;
use App\CustHub\Model\ChCustomerService;
use App\CustHub\Model\ChRobot;
use App\CustHub\Model\ChRoom;
use App\CustHub\Model\ChTalkRecord;
use App\CustHub\Model\ChTalkSession;
use App\Robot\Service\RobotMsgService;
use Carbon\Carbon;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Mine\Abstracts\AbstractService;
use Mine\Exception\NormalStatusException;
use Nette\Utils\Random;
use function Hyperf\Collection\value;

class TalkSessionService extends AbstractService
{

    #[Inject]
    protected ChCustomerServiceMapper $customerServiceMapper;

    private $repository;

    #[Inject]
    protected ChRobotMapper $robotMapper;

    public function __construct(ChTalkSession $repository)
    {
        $this->repository = $repository;
    }

    /**
     * 创建聊天列表记录
     *
     * @param int  $user_id     用户ID
     * @param int  $receiver_id 接收者ID
     * @param int  $talk_type   创建类型[1:私聊;2:群聊;]
     * @param bool $is_robot
     * @return array
     */
    public function create(int $mainUid,mixed $robotId,mixed $user_id, mixed $receiver_id, int $talk_type, bool $is_robot = false): array
    {
        $result = $this->repository->updateOrCreate([
            'main_uid'    => $mainUid,
            'user_id'     => $user_id,
            'robot_id'    => $robotId,
            'receiver_id' => $receiver_id,
            'talk_type'   => $talk_type
        ], [
            'is_top'     => 0,
            'is_delete'  => 0,
            'is_disturb' => 0,
            'is_robot'   => intval($is_robot),
        ]);

        return [
            'id'          => $result->id,
            'talk_type'   => $result->talk_type,
            'robot_id'    => $result->robot_id,
            'receiver_id' => $result->receiver_id,
        ];
    }

    /**
     * 聊天对话列表置顶操作
     *
     * @param int  $user_id    用户ID
     * @param int  $session_id 会话列表ID
     * @param bool $is_top     是否置顶（true:是 false:否）
     * @return bool
     */
    public function top(int $user_id, int $session_id, bool $is_top = true): bool
    {
        return (bool)$this->repository->update(['id' => $session_id, 'user_id' => $user_id], ['is_top' => $is_top ? 1 : 0]);
    }

    public function change(int $userId,int $sessionId,bool $type,string $field): bool|int
    {
        $info = ChTalkSession::query()
            ->where('id',$sessionId)
            ->where('user_id',$userId)
            ->first();

        if(empty($info)){
            return false;
        }

        $rst = ChTalkSession::query()
            ->where('id',$sessionId)
            ->where('user_id',$userId)
            ->update([$field=>$type ? 1 : 0]);
        if($rst){
            UnreadTalkCache::getInstance()->reset($userId,$info->robot_id,$info->talk_type, $info->receiver_id);
        }
        return $rst;
    }


    public function batchChange(int $userId,array $sessionId,string $field): bool|int
    {
        $rst = ChTalkSession::query()
            ->whereIn('id',$sessionId)
            ->where('user_id',$userId)
            ->update([
                $field=>0
            ]);

        return $rst;
    }

    /**
     * 删除会话列表
     *
     * @param int $user_id    用户ID
     * @param int $session_id 会话列表ID
     * @return bool
     */
    public function deleteSession(int $user_id, int $session_id): mixed
    {
        return ChTalkSession::query()->where('id',$session_id)->where('user_id',$user_id)->update(['is_delete' => 1]);
    }

    /**
     * 删除会话列表
     *
     * @param int $user_id     用户ID
     * @param int $receiver_id 接受者ID
     * @param int $talk_type   对话类型
     * @return bool
     */
    public function deleteByType(int $user_id, int $receiver_id, int $talk_type): bool
    {
        return (bool)$this->repository->update(['user_id' => $user_id, 'talk_type' => $talk_type, 'receiver_id' => $receiver_id], ['is_delete' => 1]);
    }

    /**
     * 获取用户的聊天列表
     *
     * @param mixed $robotId 机器人ID
     * @return array
     */
    public function getTalkList(mixed $robotId,mixed $user_id,$type,string $keyword = '',int $pageSize = 10)
    {
        $customerServiceInfo = $this->customerServiceMapper->findById($user_id);
        $robotIds =$customerServiceInfo->robots()->pluck('robot_id')->toArray();
        $mainUid = $customerServiceInfo->main_uid;
        $filed = [
            'list.id','list.robot_id','ch_robot.nickname as robot_nickname','ch_robot.avatar as robot_avatar','ch_robot.corp_name as robot_corp_name', 'list.talk_type', 'list.receiver_id', 'list.updated_at', 'list.is_disturb', 'list.is_top', 'list.is_hidden', 'list.is_pending', 'list.is_blocked', 'list.is_robot',
            'ch_contact.avatar as user_avatar', 'ch_contact.nickname','ch_contact.remark', 'ch_contact.gender',
            'ch_room.room_name as group_name', 'ch_room.room_avatar_url as group_avatar','ch_room.room_is_forbid_change_name'
        ];
        $rows = ChTalkSession::from('ch_talk_session as list')
            ->leftJoin('ch_contact', function ($join) use ($robotId,$robotIds) {
                $join->on('ch_contact.user_id', '=', 'list.receiver_id')
                    ->where(function ($query) use ($robotId,$robotIds){
                        if(empty($robotId)){
                            $query->whereIn('ch_contact.robot_id',$robotIds);
                        }else{
                            $query->where('ch_contact.robot_id',$robotId);
                        }
                    })
                    ->where('list.talk_type', '=', TalkModeConstant::PRIVATE_CHAT);
            })
            ->leftJoin('ch_room', function ($join) use ($mainUid) {
                $join->on('ch_room.room_wxid', '=', 'list.receiver_id')
                    ->where('ch_room.main_uid', '=', $mainUid)
                    ->where('list.talk_type', '=', TalkModeConstant::GROUP_CHAT);
            })
            ->join('ch_robot','ch_robot.id','=','list.robot_id')
            ->where('list.user_id', '=', $user_id)
            ->when(!empty($robotId),function ($query) use ($robotId){
                $query->where('list.robot_id', '=', $robotId);
            })
            ->when(!empty($type),function ($query) use ($type){
                if($type == 2){
                    $query->where('list.talk_type', '=', TalkModeConstant::PRIVATE_CHAT);
                }elseif ($type == 3){
                    $query->where('list.talk_type', '=', TalkModeConstant::GROUP_CHAT);
                }
            })
            ->where('list.is_blocked',0)
            ->where('list.is_delete', 0)
            ->when(!empty($keyword),function ($query)  use ($keyword){
                $query->where('ch_contact.nickname', 'like', "%{$keyword}%")
                    ->orWhere('ch_room.room_name', 'like', "%{$keyword}%");
            })
            ->groupBy('list.receiver_id')
            ->orderByRaw('list.is_top desc,list.updated_at desc')
            ->select($filed)
            ->paginate($pageSize);

        $rows->getCollection()->transform(function ($item) use ($user_id,$type) {
            $item=$item->toArray();
            $data = ChTalkSession::item([
                'id'          => $item['id'],
                'robot_id'    => $item['robot_id'],
                'talk_type'   => $item['talk_type'],
                'receiver_id' => $item['receiver_id'],
                'robot_nickname' => $item['robot_nickname'],
                'robot_avatar' => $item['robot_avatar'],
                'robot_corp_name' => $item['robot_corp_name'],
                'is_top'      => $item['is_top'],
                'is_disturb'  => $item['is_disturb'],
                'is_hidden'   => $item['is_hidden'],
                'is_pending'  => $item['is_pending'],
                'is_blocked'  => $item['is_blocked'],
                'is_robot'    => $item['is_robot'],
                'updated_at'  => Carbon::parse($item['updated_at'])->toDateTimeString(),
            ]);

            $robotId = $item['robot_id'];

            if ($item['talk_type'] == TalkModeConstant::PRIVATE_CHAT) {
                $data['name']        = $item['nickname'];
                $data['avatar']      = $item['user_avatar'];
//                $data['is_online']   = (int)di()->get(SocketClientService::class)->isOnlineAll($item['receiver_id'], $runIdAll);
                $data['remark_name'] = $item['remark'];
            } else if ($item['talk_type'] == TalkModeConstant::GROUP_CHAT) {
                $data['name']   = strval($item['group_name']);
                $data['avatar'] = $item['group_avatar'];
                $data['room_is_forbid_change_name'] = $item['room_is_forbid_change_name'];
            }

            //未读消息数
            $data['unread_num']  = UnreadTalkCache::getInstance()->read($user_id,$robotId, $item['talk_type'], $item['receiver_id']);

            $records = LastMessage::getInstance()->read($data['talk_type'], $robotId, $data['receiver_id']);
            if ($records) {
                $data['msg_text']   = $records['text'];
                $data['updated_at'] = $records['created_at'];
            }
            $data['gender_text'] = GenderConstants::getMessage($item['gender']);
            return $data;
        });

        $result =  $this->robotMapper->setPaginate($rows);

        $items = $result['items'];
        if($type == 1){
            $items = array_filter($items, function ($item) {
                return $item['unread_num'] > 0;
            });
            $items = array_values($items);
            $result['items'] = $items;
        }
        return $result;
    }

    /**
     * 设置消息免打扰
     *
     * @param int $user_id     用户ID
     * @param int $receiver_id 接收者ID
     * @param int $talk_type   对话类型[1:私信;2:群聊;]
     * @param int $is_disturb  是否免打扰[0:否;1:是;]
     * @return boolean
     */
    public function disturb(int $user_id, int $receiver_id, int $talk_type, int $is_disturb): bool
    {
        $result = $this->repository->first([
            'user_id'     => $user_id,
            'talk_type'   => $talk_type,
            'receiver_id' => $receiver_id,
        ], ['id', 'is_disturb']);

        if (!$result || $is_disturb == $result->is_disturb) {
            return false;
        }

        return (bool)$this->repository->update(['id' => $result->id], ['is_disturb' => $is_disturb]);
    }

    /**
     * 判断是否消息免打扰
     *
     * @param int $user_id     用户ID
     * @param int $receiver_id 接收者ID
     * @param int $talk_type   对话类型[1:私信;2:群聊;]
     * @return bool
     */
    public function isDisturb(int $user_id, int $receiver_id, int $talk_type): bool
    {
        return (bool)$this->repository->value([
            'user_id'     => $user_id,
            'talk_type'   => $talk_type,
            'receiver_id' => $receiver_id,
        ], "is_disturb");
    }

    public function download(mixed $uid,mixed $id)
    {
        $info = ChTalkRecord::query()
            ->where('id',$id)
            ->where('user_id',$uid)
            ->first();

        if(empty($info)){
            throw new NormalStatusException('请选择您要下载的文件');
        }

        $content = $info->content;

        $robotInfo = ChRobot::query()
            ->where('id',$info->robot_id)
            ->first();

        if($info->msg_type == MsgTypeConstants::MINI_PROGRAM){
            if(!empty($content['content']['cover_url'])){
                return $content['content']['cover_url'];
            }
            $msgData = $info->msg_data['msg_data'];
            $robotApiService = make(Robot::class, [$robotInfo->server_id, $robotInfo->robot_key])->gateway();
            $result = $robotApiService->wxWorkDownload(
                $msgData['cover_image_aes_key'],
                $msgData['cover_image_id'],
                $msgData['cover_image_size'], 1,Random::generate(20).'.jpg');
            if($result === false){
                throw new NormalStatusException('下载失败');
            }
            $url = $result['url'] ?? '';
            $content['content']['cover_url'] = $url;
        }else{
            if(!empty($content['content'])){
                return $content['content'];
            }
            $url = container()->get(RobotMsgService::class)->processMessages($robotInfo,$info->msg_type,$info->msg_data);
            if($url === false){
                throw new NormalStatusException('下载失败');
            }
            $content['content'] = $url;
        }
        $info->content = $content;
        $info->save();
        return $url;
    }

    public function sort(int $uid, mixed $sourceId, mixed $targetId): bool
    {
        $items = Db::table('ch_customer_service_robot')
            ->where('customer_service_id',$uid)
            ->whereIn('robot_id', [$sourceId, $targetId])
            ->pluck('sort', 'robot_id')
            ->toArray();

        if (count($items) !== 2) {
            return false;
        }

        $sourceSort = $items[$sourceId];
        $targetSort = $items[$targetId];

        // 交换排序
        Db::transaction(function () use ($uid, $sourceId, $targetId, $sourceSort, $targetSort) {
            Db::table('ch_customer_service_robot')
                ->where('customer_service_id',$uid)
                ->where('robot_id', $sourceId)
                ->update(['sort' => $targetSort]);
            Db::table('ch_customer_service_robot')
                ->where('customer_service_id',$uid)
                ->where('robot_id', $targetId)
                ->update(['sort' => $sourceSort]);
        });

        return true;
    }

    public function modifyRoomName(int $uid,mixed $id,string $roomName): bool|int
    {
        $info = ChTalkSession::query()
            ->where('id',$id)
            ->where('user_id',$uid)
            ->first();
        if(empty($info)){
            throw new NormalStatusException('请选择您要修改的群聊');
        }

        if($info->talk_type != TalkModeConstant::GROUP_CHAT){
            throw new NormalStatusException('请选择您要修改的群聊');
        }

        $robotInfo = $this->robotMapper->findById($info->robot_id);

        $api = make(Robot::class, [$robotInfo->server_id, $robotInfo->uuid])->gateway();

        $response = $api->editRoomName($info->receiver_id,$roomName);

        if($response === false){
            throw new NormalStatusException('修改群聊名称失败');
        }

        $rst = ChRoom::query()
            ->where('main_uid',$info->main_uid)
            ->where('room_wxid',$info->receiver_id)
            ->update([
                'room_name' => $roomName,
            ]);
        return $rst;
    }

    public function addFriend(int $uid,mixed $id,string $verify_text): bool
    {
        $info = ChTalkSession::query()
            ->where('id',$id)
            ->where('user_id',$uid)
            ->first();
        if(empty($info)){
            throw new NormalStatusException('请选择您要添加的好友');
        }

        $check = ChContact::query()
            ->where('robot_id',$info->robot_id)
            ->where('user_id',$info->receiver_id)
            ->where('status',ContactStatusConstants::NORMAL_FRIEND)
            ->exists();
        if($check){
            throw new NormalStatusException('该用户已经是您的好友');
        }

        $robotInfo = $this->robotMapper->findById($info->robot_id);
        empty($verify_text) && $verify_text = '我是，'.$robotInfo->nickname;
        $api = make(Robot::class, [$robotInfo->server_id, $robotInfo->uuid])->gateway();
        $response = $api->addDeletedContact($info->receiver_id,$verify_text);
        if($response === false){
            throw new NormalStatusException('发送失败'.$api->getErrorMsg());
        }
        return true;
    }

    public function getUnreadNum($id)
    {
       $num = ChTalkSession::query()
            ->where('id',$id)
            ->value('unread_num');
        return $num ? $num : 0;
    }

    public function increment($id): void
    {
        ChTalkSession::query()
            ->where('id',$id)
            ->increment('unread_num');
    }

    public function decrement($id): void
    {
        ChTalkSession::query()
            ->where('id',$id)
            ->decrement('unread_num');
    }

    public function reset($id): void
    {
        ChTalkSession::query()
            ->where('id',$id)
            ->update([
                'unread_num' => 0,
            ]);
    }
}
